/**
 * Created by WLG on 2018/11/12.
 */
const mongoose = require('mongoose');
const redisDB = require('../lib/redisManage');
const MemOnlineInfo = require('../model/sysMemOnlineInfo');
let serverConfig = require('../config/serverConfig');
let AccountMemService = require('../services/accountMemService');
let CommonUtil = require('../lib/commonUtil');
let Chat = mongoose.model('Chat');
let SocketInfo = require('../model/sysSocketInfo');
let SocketPushService = require('./socketPushService');
/**
 * 在线信息服务
 * 维护在线用户信息
 * 维护在线用户ChatMemInfo
 */
class OnlineService{
    /**
     * 登录
     * @param io
     * @param username
     * @param terminalType
     * @param socketId
     * @returns {Promise.<*>}
     */
    static async memLogin(io, username, terminalType, socketId){
        let am = await AccountMemService.load({username:username});
        let memOnlineInfo = await this.getMemOnlineInfoCache(am._id);
        if(!memOnlineInfo){
            memOnlineInfo = new MemOnlineInfo();
            memOnlineInfo.memInfo = am;
        }
        let socketInfo = new SocketInfo(terminalType,socketId,new Date().getTime());
        let needCloseSocketArray = await this.addSocketInfoAndJudgeCloseSocket(io, memOnlineInfo, terminalType, socketInfo);
        //存完再关
        await this.setSocketMemCache(socketId,am._id);
        await this.setMemOnlineInfoCache(am._id,memOnlineInfo);
        /**
         * 如果不这样写会出现提前触发 socket 断开事件
         * 从而提前删除了一次第一个socket,导致重复删除
         */
        for(let attr in needCloseSocketArray){
            SocketPushService.pushCloseMsgAndClose(io,needCloseSocketArray[attr]);
        }

        return am;
    }

    static async setMemOnlineInfoCache(memId,memOnlineInfo){
        return await redisDB.set(this.createKey(memId),memOnlineInfo,serverConfig.socketCommonCacheTime);
    }
    static async getMemOnlineInfoCache(memId){
        return await redisDB.get(this.createKey(memId));
    }
    static async delMemOnlineInfoCache(memId){
        return await redisDB.del(this.createKey(memId));
    }
    static createKey(id){
        return "OnlineMem:" + id;
    }

    static async getSocketMemCache(socket){
        return await redisDB.get(this.createSocketMemKey(socket));
    }
    static async setSocketMemCache(socket,memId){
        return await redisDB.set(this.createSocketMemKey(socket),memId,serverConfig.socketCommonCacheTime);
    }
    static async delSocketMemCache(socket){
        return await redisDB.del(this.createSocketMemKey(socket));
    }
    static createSocketMemKey(socket){
        return "SocketMem:" + socket;
    }

    /**
     * 添加socketInfo并判断是否关闭旧的socket
     * @param io
     * @param memOnlineInfo
     * @param terminalType
     * @param socketInfo
     * @returns {Promise.<void>}
     */
    static async addSocketInfoAndJudgeCloseSocket(io,memOnlineInfo,terminalType,socketInfo){
        console.log(this.getTerminalSocketSize(memOnlineInfo, terminalType), '-', serverConfig.terminalSize[terminalType]);
        let dif = this.getTerminalSocketSize(memOnlineInfo,terminalType) - serverConfig.terminalSize[terminalType];
        //CommonUtil.consoleRed('memOnlineInfo',memOnlineInfo);
        let needCloseSocketArray = [];
        if(dif>=0){
            for(let i =0 ; i <= dif ; i++){
                let socketId = this.removeFirstTerminalSocket(memOnlineInfo,terminalType);
                needCloseSocketArray.push(socketId);
                await this.delSocketMemCache(socketId);
            }
        }
        this.getTerminalSocketIDGroupByTerminalType(memOnlineInfo,terminalType).push(socketInfo.socketID);
        memOnlineInfo.socketMap[socketInfo.socketID] = socketInfo;
        return needCloseSocketArray;
    }

    /**
     * 根据 终端类型 获取终端SoketID组
     * @param memOnlineInfo
     * @param terminalType
     * @returns {*}
     */
    static getTerminalSocketIDGroupByTerminalType(memOnlineInfo,terminalType){
        let terminalSocketIDGroup = memOnlineInfo.terminalSocketIDGroup[terminalType];
        if(!terminalSocketIDGroup){
            terminalSocketIDGroup = memOnlineInfo.terminalSocketIDGroup[terminalType] = [];
        }
        return terminalSocketIDGroup;
    }

    /**
     * 删除socketInfo
     * @param socketID
     * @returns {Promise.<void>}
     */
        static async removeSocketInfo(socketID){
        let memId = await this.getSocketMemCache(socketID);
        if(memId){
            let memOnlineInfo = await this.getMemOnlineInfoCache(memId);

            logInfo.info(memOnlineInfo.memInfo);

            let socketInfo = memOnlineInfo.socketMap[socketID];
            if(socketInfo){
                let terminalType = socketInfo.terminalType;
                let socketIDGroup = memOnlineInfo.terminalSocketIDGroup[terminalType];
                memOnlineInfo.terminalSocketIDGroup[terminalType] = CommonUtil.arrayRemoveOne(socketIDGroup,socketID);
                delete memOnlineInfo.socketMap[socketID];
                let map = memOnlineInfo.socketMap;
                if(Object.getOwnPropertyNames(map) == 0){
                    await this.delMemOnlineInfoCache(memId);
                }else{
                    await this.setMemOnlineInfoCache(memId,memOnlineInfo);
                }

                this.delSocketMemCache(socketID);
            }
        }
    }
    static getTerminalSocketSize(memOnlineInfo,terminalType){
        let result = memOnlineInfo.terminalSocketIDGroup[terminalType];
        if(result) {
            result = result.length;
        }else{
            result = 0;
        }
        return result;
    }
    static removeFirstTerminalSocket(memOnlineInfo,terminalType){
        let socketID = memOnlineInfo.terminalSocketIDGroup[terminalType].shift();
        //CommonUtil.consoleRed("removeFirstTerminalSocket:",socketID);
        delete memOnlineInfo.socketMap[socketID];
        return socketID;
    }
}

module.exports = OnlineService;